package org.fujene.term;

/**
 * 文字列の変換やエスケープ処理を行います。
 *
 * @author yasuda
 *
 */
public class Escaper {

	private static char[] GAP_OF_MAPPING_SJIS = {
		'\u301c',	//～ (1-33, WAVE DASH)
		'\u2016',	//∥ (1-34, DOUBLE VERTICAL LINE)
		'\u2212',	//－ (1-61, MINUS SIGN)
		'\u00a2',	//￠ (1-81, CENT SIGN)
		'\u00a3',	//￡ (1-82, POUND SIGN)
		'\u00ac',	//￢ (2-44, NOT SIGN)
		'\u2014'	//― (1-29, EM DASH)
	};

	private static char[] GAP_OF_MAPPING_MS932 = {
		'\uff5e',	//～ (1-33, WAVE DASH)
		'\u2225',	//∥ (1-34, DOUBLE VERTICAL LINE)
		'\uff0d',	//－ (1-61, MINUS SIGN)
		'\uffe0',	//￠ (1-81, CENT SIGN)
		'\uffe1',	//￡ (1-82, POUND SIGN)
		'\uffe2',	//￢ (2-44, NOT SIGN)
		'\u2015'	//― (1-29, EM DASH)
	};

	private static char[] ENTITY_REF_ORIGIN = {
		'&',
		'\"',
		'<',
		'>'
	};

	private static String[] ENTITY_REF = {
		"&amp;",
		"&quot;",
		"&lt;",
		"&gt;"
	};

	private static char[] JSON_ESCAPE_MAP_ORIGIN = {
		'\"',
		'\'',
		'\r',
		'\n'
	};

	private static String[] JSON_ESCAPE_MAP = {
		"\\\"",
		"\\\'",
		"",
		""
	};

	/**
	 * Javaのマッピングテーブルがズレている文字のマッピングを強制的に変換
	 * （SJISからMS932へ）
	 * @param str
	 * @return
	 */
	public static String convertSJISToMS932(String str) {
		if(str == null)
			return str;

		StringBuilder builder = new StringBuilder();
		for(char c : str.toCharArray()){
			boolean isMapped = false;
			for(int i = 0 ; i < GAP_OF_MAPPING_SJIS.length ; i++){
				if(c == GAP_OF_MAPPING_SJIS[i]){
					builder.append(GAP_OF_MAPPING_MS932[i]);
					isMapped = true;
					break;
				}
			}
			if(!isMapped)
				builder.append(c);
		}
		return builder.toString();
/*
		 //dirty code
		return str.replaceAll("\u301c", "\uff5e")	//～ (1-33, WAVE DASH)
			.replaceAll("\u2016", "\u2225")		//∥ (1-34, DOUBLE VERTICAL LINE)
			.replaceAll("\u2212", "\uff0d")		//－ (1-61, MINUS SIGN)
			.replaceAll("\u00a2", "\uffe0")		//￠ (1-81, CENT SIGN)
			.replaceAll("\u00a3", "\uffe1")		//￡ (1-82, POUND SIGN)
			.replaceAll("\u00ac", "\uffe2")		//￢ (2-44, NOT SIGN)
			.replaceAll("\u2014", "\u2015");	//― (1-29, EM DASH)
*/
	}

	/**
	 * Javaのマッピングテーブルがズレている文字のマッピングを強制的に変換
	 * （MS932からSJISへ）
	 * @param str
	 * @return
	 */
	public static String convertMS932ToSJIS(String str) {
		if(str == null)
			return str;

		StringBuilder builder = new StringBuilder();
		for(char c : str.toCharArray()){
			boolean isMapped = false;
			for(int i = 0 ; i < GAP_OF_MAPPING_MS932.length ; i++){
				if(c == GAP_OF_MAPPING_MS932[i]){
					builder.append(GAP_OF_MAPPING_SJIS[i]);
					isMapped = true;
					break;
				}
			}
			if(!isMapped)
				builder.append(c);
		}
		return builder.toString();
		/*
		 //dirty code
		return str.replaceAll("\uff5e", "\u301c")	//～ (1-33, WAVE DASH)
			.replaceAll("\u2225", "\u2016")		//∥ (1-34, DOUBLE VERTICAL LINE)
			.replaceAll("\uff0d", "\u2212")		//－ (1-61, MINUS SIGN)
			.replaceAll("\uffe0", "\u00a2")		//￠ (1-81, CENT SIGN)
			.replaceAll("\uffe1", "\u00a3")		//￡ (1-82, POUND SIGN)
			.replaceAll("\uffe2", "\u00ac")		//￢ (2-44, NOT SIGN)
			.replaceAll("\u2015", "\u2014");	//― (1-29, EM DASH)
			*/
	}

	/**
	 * 文字列中の実体参照文字をエスケープ処理します。
	 *
	 * @param str
	 * @return	実体参照文字をエスケープした後の文字列
	 */
	public static String escapeEntityRef(String str){
		if(str == null)
			return str;

		StringBuilder builder = new StringBuilder();
		for(char c : str.toCharArray()){
			boolean isMapped = false;
			for(int i = 0 ; i < ENTITY_REF_ORIGIN.length ; i++){
				if(c == ENTITY_REF_ORIGIN[i]){
					builder.append(ENTITY_REF[i]);
					isMapped = true;
					break;
				}
			}
			if(!isMapped)
				builder.append(c);
		}
		return builder.toString();
	}

	/**
	 * 文字列中の実体参照文字をアンエスケープ処理します。
	 *
	 * @param str
	 * @return	実体参照文字をエスケープした後の文字列
	 */
	public static String unescapeEntityRef(String str){
		if(str == null ){
			return str;
		}

		str = str.replaceAll("&nbsp;", " ");
		str = str.replaceAll("&amp;", "&");
		str = str.replaceAll("&#38;", "&");
		str = str.replaceAll("&rsquo;", "'");
		str = str.replaceAll("&#39;", "'");
		str = str.replaceAll("&quot;", "\"");
		str = str.replaceAll("&#34;", "\"");
		str = str.replaceAll("&lt;", "<");
		str = str.replaceAll("&#60;", "<");
		str = str.replaceAll("&gt;", ">");
		str = str.replaceAll("&#62;", ">");
		str = str.replaceAll("&yen;", "\\\\");
		str = str.replaceAll("&#59;", ";");
		str = str.replaceAll("&#92;", "\\\\");
		str = str.replaceAll("&hellip;", "…");
		str = str.replaceAll("&rarr;", "→");
		str = str.replaceAll("&larr;", "←");
		str = str.replaceAll("&acute;", "´");
		str = str.replaceAll("&rdquo;", "“");
		str = str.replaceAll("&ldquo;", "”");
		//TODO 本当はもっと多い。があまりにも多すぎるので、表示上問題がおきないレベルで対応

		return str;
	}

	/**
	 * 文字列中の実体参照文字のうち、空白文字のみをエスケープ処理します。
	 *
	 * @param str
	 * @return	実体参照文字をエスケープした後の文字列
	 */
	public static String escapeEntityRefOnlySpace(String str){
		if(str == null)
			return null;

        StringBuilder result = new StringBuilder();
        char[] chars = str.toCharArray();
        boolean isTag = false;
        for(int i=0; i < chars.length ; i++){
            if(chars[i] == '<'){
                isTag = true;
            }else if(chars[i] == '>'){
                isTag = false;
            }

            if(isTag){
            	result.append(chars[i]);
            }else{
            	result.append(chars[i] == '\u0020' ? "&nbsp;" : chars[i]);
            }
        }
        return result.toString();

	}

	/**
	 * JSONデータ形式の値として使用ができない文字列をエスケープ処理、もしくは除去するメソッドです。
	 * エスケープ：ダブルコーテーション、シングルコーテーション
	 * 除去：改行文字、復帰文字
	 *
	 * @param str
	 * @return
	 */
	public static String escapeForJson(String str){
		if(str == null)
			return str;

		StringBuilder builder = new StringBuilder();
		for(char c : str.toCharArray()){
			boolean isMapped = false;
			for(int i = 0 ; i < JSON_ESCAPE_MAP_ORIGIN.length ; i++){
				if(c == JSON_ESCAPE_MAP_ORIGIN[i]){
					builder.append(JSON_ESCAPE_MAP[i]);
					isMapped = true;
					break;
				}
			}
			if(!isMapped)
				builder.append(c);
		}
		return builder.toString();

		/*
		//dirty code
		str = str.replace("\"", "\\\"");
		str = str.replace("\'", "\\\'");
		str = str.replace("\r", "");
		str = str.replace("\n", "");

		return str;
		*/
	}

	/**
	 * brタグを改行文字に置換します。
	 */
	public static String convertBrToNewLine(String str){
		if(str == null) {
			return str;
		}

		return str.replaceAll("<[b|B][r|R][\\s]*/?>", System.getProperty("line.separator"));
	}
}

